// 重写数组方法

// 获取数组的原始方法
let oldArrayPrototypeMethods = Array.prototype;

// 继承，Object.create创建一个对象，将该对象的原型指向入参
export const ArrayMethods = Object.create(oldArrayPrototypeMethods);

// 劫持，vue将改变数组的 7 个方法进行了重写，其它的方法继续走 oldArrayPrototypeMethods 的
let methods = [
  'push',
  'unshift',
  'pop',
  'shift',
  'splice',
  'sort',
  'reverse'
];

methods.forEach(item => {
  ArrayMethods[item] = function (...args) {
    // args是参数数组
    // console.log("数组劫持，目的是为了监听到数组的变化");
    /**
     * 为啥不直接用observer(args)呢？
     *    因为args是使用数组方法时的参数数组，里面不是所有的参数都需要observer的
     *    还是得分门别类的使用，例如splice的第3个参数是被插入到数组，并且改变原数组的
     *    它是需要被监听的
     */
    // 下面的this指向数组，也即Observer类的入参value，而每个value上定义了一个__ob__属性
    // __ob__即为Observer的实例对象
    // 也即__ob__上有Observer类上的原型方法
    let ob = this.__ob__;
    let inserted = null;
    let result = oldArrayPrototypeMethods[item].apply(this, args);
    switch (item) {
      // 插入到数组的数据进行劫持
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        // 对可能存在的需要插入进去的数据进行劫持，第3个参数
        inserted = args.splice(2); // args.slice(2)也行
        break;
      default:
        break;
      // 至于将数据从数组剔出去，或者排序、反向等，应该不需要对这些数据进行监听
      // 并且它们本来在之前数据初始化的时候就已经监听过了
    }
    if (inserted) {
      ob.observerArray(inserted);
      // 触发数组更新
      ob.dep.notify(); // watcher执行
    }
    // 不能在下面直接return oldArrayPrototypeMethods[item].apply(this, args);
    // **不然，结果还没有得到，上面的watcher就执行了，这个时候渲染的还是旧数据**
    return result;
  }
})